--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[

    技能指示物品。

]]--
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- PARAM   
    local SPELL_CD_TIME = 5         -- CD 时间
    local RECHARGE_VALUE_COST = 1   -- 充能值消耗
    local HUNGER_VALUE_COST = 0     -- 饥饿值消耗
    local MAX_DISTANCE = 12         -- 最大距离
    local DAMAGE = 50               -- 伤害
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local assets =
{
    -- Asset("ANIM", "anim/cane.zip"),
    -- Asset("ANIM", "anim/swap_cane.zip"),
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---
    -- local delta_search_distance = 0.2
    -- local function GetMaxPassablePoint(start_pt,end_pt)
    --     --- 先归一化
    --     local Normalize_Vect = (end_pt - start_pt):Normalize()
    --     -- 以0.2为间隔检查 
    --     local max_distance = 0
    --     for i = 0,MAX_DISTANCE,delta_search_distance do
    --         local pt = start_pt + Normalize_Vect * i
    --         if TheWorld.Map:IsPassableAtPoint(pt.x,0,pt.z) then
    --             max_distance = i
    --         end
    --     end
    --     local pt = start_pt + Normalize_Vect * max_distance
    --     return pt
    -- end

    ---- 反向寻找，从最远处开始寻找。
    local delta_search_distance = 0.2
    local function GetMaxPassablePoint(start_pt, end_pt)
        -- 减少计算量
        if TheWorld.Map:IsPassableAtPoint(end_pt.x, 0, end_pt.z) then
            return end_pt
        end
        -- 归一化方向向量
        local Normalize_Vect = (end_pt - start_pt):Normalize()        
        -- 计算两点之间的距离
        local total_distance = math.min((end_pt - start_pt):Length(), MAX_DISTANCE)
        -- 从最远端开始，逐步向前检查
        for i = total_distance, 0, -delta_search_distance do
            local pt = start_pt + Normalize_Vect * i
            if TheWorld.Map:IsPassableAtPoint(pt.x, 0, pt.z) then
                -- 找到第一个可通过的点即返回
                return pt
            end
        end        
        -- 如果没有找到任何可通过的点，则返回起点
        return start_pt
    end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 最大距离指示器
    local function CreateMaxPointIndicator(inst,master_fx)
        if not TheInput then
            return
        end
        local owner = inst.replica.loramia_com_item_spell:GetOwner()
        -- local fx = SpawnPrefab("loramia_sfx_dotted_circle_client")
        -- fx:PushEvent("Set",{range = 1 ,pt = Vector3(owner.Transform:GetWorldPosition())})
        local fx = SpawnPrefab("reticule")
        fx.Transform:SetPosition(owner.Transform:GetWorldPosition())
        fx.AnimState:SetAddColour(1, 1, 0, 0)
        fx.AnimState:SetMultColour(1, 1, 0, 1)
        fx.AnimState:SetBloomEffectHandle("shaders/anim.ksh")
        if master_fx then
            master_fx.AnimState:SetAddColour(1, 1, 0, 0)
            master_fx.AnimState:SetMultColour(1, 1, 0, 1)
            master_fx.AnimState:SetBloomEffectHandle("shaders/anim.ksh")
        end
        inst:ListenForEvent("onremove",function()
            fx:Remove()
        end)
        local update_fn = function()
            local mouse_pt = TheInput:GetWorldPosition()
            fx.Transform:SetPosition(mouse_pt.x,0,mouse_pt.z)
            local owner_pt = Vector3(owner.Transform:GetWorldPosition())
            local pt = GetMaxPassablePoint(owner_pt,mouse_pt)
            fx.Transform:SetPosition(pt.x,0,pt.z)
        end
        TheInput:Loramia_Add_Update_Modify_Fn(fx,update_fn)
    end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local function spell_com_install(inst)
    inst:ListenForEvent("Loramia_OnEntityReplicated.loramia_com_item_spell",function(inst,replica_com)
        replica_com:Set_Dotted_Circle_Radius(10)
        replica_com:Set_Mouse_Left_Click_Fn(function(inst,owner,pt,target)
                        --- 往物品自身发送event
                        replica_com:PushEvent("left_clicked",{pt = Vector3(pt.x,0,pt.z)})
        end)
        replica_com:Set_Mouse_Right_Click_Fn(function(inst,owner,pt,target)
                        --- 往物品自身发送event
                        replica_com:PushEvent("right_clicked",{})
        end)
        replica_com.indicator_type = "arrow" -- "circle" or "arrow"
    end)
    inst:ListenForEvent("indicator_acitved",CreateMaxPointIndicator)
    if not TheWorld.ismastersim then
        return
    end
    inst:AddComponent("loramia_com_item_spell")
    inst.components.loramia_com_item_spell:SetNeed2CloseController(false)
    -----------------------------------------------------------------------------
    ---
        inst.components.loramia_com_item_spell:SetTestFn(function(inst,doer)
            if doer.components.loramia_com_spell_controller:IsReady("creation_impact")
                and not doer.components.loramia_com_spell_controller:NetGetData("energy_saving_mode")  -- 节能模式。
                and doer.components.loramia_com_talent_tree:IsUnlocked("creation_impact")  -- 技能是否解锁
                and (doer.components.loramia_com_recharge:GetCurrent() >= RECHARGE_VALUE_COST or TUNING.LORAMIA_DEBUGGING_MODE)
                and doer.components.hunger.current >= HUNGER_VALUE_COST
                then
                -- print("loramia_spell_creation_impact test true ")
                return true
            end
            -- print("loramia_spell_creation_impact test false ")
            return false
        end)
    -----------------------------------------------------------------------------
    ---
        inst:ListenForEvent("left_clicked",function(inst,_table)
            -- print("loramia_spell_creation_impact left_clicked +++++++++++++++ ",_table.pt.x,_table.pt.y,_table.pt.z)
            -----------------------------------------------------------------------------------------------
            ---
                local owner = inst.components.loramia_com_item_spell:GetOwner()
                owner.components.loramia_com_spell_controller:StartTimer("creation_impact",SPELL_CD_TIME)
                if not TUNING.LORAMIA_DEBUGGING_MODE then
                    owner.components.loramia_com_recharge:DoDelta(-RECHARGE_VALUE_COST)
                end
                owner.components.hunger:DoDelta(-HUNGER_VALUE_COST,true)
            -----------------------------------------------------------------------------------------------
            ---
                local start_pt = Vector3(owner.Transform:GetWorldPosition())
                local end_pt = Vector3(_table.pt.x,0,_table.pt.z)
            -----------------------------------------------------------------------------------------------
            -- --- 归一化方向
                local Normalize_Vect = (end_pt - start_pt):Normalize()
            -- -----------------------------------------------------------------------------------------------
            -- --- 以0.2为间隔，从0开始计算检查
            --     local max_distance = 0
            --     for i = 0,MAX_DISTANCE,0.2 do
            --         local pt = start_pt + Normalize_Vect * i
            --         if TheWorld.Map:IsPassableAtPoint(pt.x,0,pt.z) then
            --             max_distance = i
            --         end
            --     end
            --     local pt = start_pt + Normalize_Vect * max_distance
            -----------------------------------------------------------------------------------------------
            ---
                local pt = GetMaxPassablePoint(start_pt,end_pt)
            -----------------------------------------------------------------------------------------------
            ---
                owner.sg:GoToState("loramia_sg_spurt",{targetpos = pt})
            -----------------------------------------------------------------------------------------------
            --- 创建特效
                local BOUNCE_MUST_TAGS = { "_combat" }
                local BOUNCE_NO_TAGS = { "INLIMBO", "wall", "notarget", "player", "companion", "flight", "invisible", "noattack", "hiding" }
                local hit_targets = {}
                SpawnPrefab("loramia_spell_line_laser_beam"):PushEvent("Set",{
                    start_pt = start_pt,
                    end_pt = (pt - Normalize_Vect*1),
                    colour = {100,100,0},
                    delta_length = 0.8,
                    delay_frame = 0.2,
                    -- onhit_delay_frame = 10,
                    onhitfn = function(x,y,z)                    
                        local ents = TheSim:FindEntities(x, 0, z, 1.2, BOUNCE_MUST_TAGS, BOUNCE_NO_TAGS)
                        for i,tempInst in ipairs(ents) do
                            if tempInst and tempInst:IsValid() and not hit_targets[tempInst] 
                                and tempInst.components.combat
                            then
                                hit_targets[tempInst] = true
                                tempInst.components.combat:GetAttacked(owner,DAMAGE,inst)
                            end
                        end
                    end,
                })
            -----------------------------------------------------------------------------------------------
            inst:Remove()
        end)
        inst:ListenForEvent("right_clicked",function(inst,_table)
            inst:Remove()
            print("取消技能")
        end)
    -----------------------------------------------------------------------------
end

local function fn()
    local inst = CreateEntity()
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()
    inst.entity:SetPristine()
    spell_com_install(inst)
    if not TheWorld.ismastersim then
        return inst
    end
    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(DAMAGE)
    return inst
end

return Prefab("loramia_spell_creation_impact", fn, assets)
